#include <stdio.h>

#define __STDC_CONSTANT_MACROS

//extern "C"
//{
    #include "libavutil/avutil.h"
    #include "libavcodec/avcodec.h "
    #include "libavformat/avformat.h"
    #include "libswscale/swscale.h"

    //#include "SDL2/SDL.h"
//}

int main(int argc, char *argv[])
{
    char input_file[] = "D:\\ldh-work\\projects\\ffmpeg\\testvideo\\Titanic.ts";
    char output_file_h264[] = "Titanic.h264";
    char output_file_yuv[] = "Titanic.yuv";

    FILE *pFileH264;
    FILE *pFileYUV;

    AVFormatContext *pFormatCtx;
    int             i, videoindex;
    AVCodecContext *pCodecCtx;
    AVCodec        *pCodec;

    AVPacket       *pPacket;
    AVFrame        *pFrame, *pFrameYUV;
    int            ret, got_picture;

    int            frame_cnt;

    uint8_t        *out_buffer;
    int            y_size;

    struct SwsContext *img_convert_ctx;

//	if ( SDL_Init(SDL_INIT_VIDEO) )
//	{
//		printf( "Could not initialize SDL - %s\n", SDL_GetError());
//		return -1;
//	}

    //SDl_Player_yuvfile(output_file_yuv, 1024, 768, 640, 272, 12);
    //return 0;

    // 注册所有组件
    av_register_all();

    avformat_network_init();

    pFormatCtx = avformat_alloc_context();

    if ( avformat_open_input(&pFormatCtx, input_file, NULL, NULL) != 0 )
    {
        printf("Could't open input stream.\n");
        return -1;
    }

    if ( avformat_find_stream_info(pFormatCtx, NULL) < 0 )
    {
        printf("Could't find stream information.\n");
        return -1;
    }

    // 找到视频流对应的编码器ID
    videoindex = -1;
    for ( i = 0; i < pFormatCtx->nb_streams; i++)
    {
        if ( pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO )
        {
            videoindex = i;
            break;
        }
    }

    pCodecCtx = pFormatCtx->streams[videoindex]->codec;
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    if ( pCodec == NULL )
    {
        printf("Codec is not found.\n");
        return -1;
    }

    if ( avcodec_open2(pCodecCtx, pCodec, NULL) < 0 )
    {
        printf("open decoder error.\n");
        return -1;
    }

    pFileH264 = fopen(output_file_h264, "wb+");
    pFileYUV = fopen(output_file_yuv, "wb+");
    if ( pFileH264 == NULL || pFileYUV == NULL )
    {
        printf("create output file error.\n");
        return -1;
    }

    pFrame = av_frame_alloc();
    pFrameYUV = av_frame_alloc();

    //pPacket = av_packet_alloc();
    pPacket = (AVPacket *)av_malloc( sizeof(AVPacket) );

    out_buffer=(uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
    avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
    //packet=(AVPacket *)av_malloc(sizeof(AVPacket));
    //Output Info-----------------------------
    printf("--------------- File Information ----------------\n");
    av_dump_format(pFormatCtx,0,input_file,0);
    printf("-------------------------------------------------\n");
    img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
        pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);


    frame_cnt = 0;

    while ( av_read_frame(pFormatCtx, pPacket) >= 0 )
    {
        if (pPacket->stream_index == videoindex)
        {
            // get ecoded data
            fwrite(pPacket->data, pPacket->size, 1, pFileH264);

            // 获取到一帧码流数据，开始解码
            if ( avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, pPacket) < 0 )
            {
                printf("Decode Error.\n");
                return -1;
            }

            if ( got_picture )
            {
                sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
                    pFrameYUV->data, pFrameYUV->linesize);

                printf("Decoded frame index: %d (%dx%d) linesize[0]=%d,linesize[1]=%d,linesize[2]=%d\n",
                frame_cnt, pFrame->width, pFrame->height,pFrameYUV->linesize[0],pFrameYUV->linesize[1],pFrameYUV->linesize[2]);

                /*
                 * 在此处添加输出YUV的代码
                 * 取自于pFrameYUV，使用fwrite()
                 */
                //fwrite(pFrame->data[0], pFrame->linesize[0] * pFrame->height *3/2, 1, pFileYUV);

                // Y： 一个字节
                fwrite(pFrameYUV->data[0], pFrameYUV->linesize[0] * pFrame->height * 1, 1, pFileYUV);
// 				char bb = 128;
// 				int cnt = pFrameYUV->linesize[0] * pFrame->height /2;
// 				while (cnt)
// 				{
// 					fwrite(&bb, 1, 1, pFileYUV);
// 					cnt--;
// 				}

                // 4：2：0 采样：

                // U: 半个字节
                fwrite(pFrameYUV->data[1], pFrameYUV->linesize[1] * pFrame->height / 2, 1, pFileYUV);

                // V: 半个字节
                fwrite(pFrameYUV->data[2], pFrameYUV->linesize[2] * pFrame->height / 2, 1, pFileYUV);

                //fwrite(pFrameYUV->data[0], pFrame->width * pFrame->height *3/2, 1, pFileYUV);
                //fwrite(pFrameYUV->data[1], pFrame->width * pFrame->height *3/4, 1, pFileYUV);
                //fwrite(pFrameYUV->data[2], pFrame->width * pFrame->height *3/4, 1, pFileYUV);

                frame_cnt ++;
            }
        }

        //av_packet_free(pPacket);
        av_free_packet(pPacket);
    }

    fclose(pFileH264);
    fclose(pFileYUV);

    av_frame_free(&pFrame);

    avcodec_close(pCodecCtx);

    avformat_close_input(&pFormatCtx);

    //SDL_Quit();

    return 0;
}

